#!/bin/bash

# set -e
# set -o pipefail

PROJDIR=$(dirname "$(cd "$(dirname "${0}")"; pwd -P)")

# {{{ Colors
RED='\033[0;31m'
BOLD_RED='\033[1;31m'
GREEN='\033[0;32m'
BOLD_GREEN='\033[1;32m'
YELLOW='\033[0;33m'
BOLD_YELLOW='\033[1;33m'
RESET='\033[0m'
# }}}

# {{{ Help message
function help() {
  cat >&2 << EOF
This script is a driver for "runtime tests".
The "runtime test" is to test gosseract package in specific environments,
such as OS, Go version and Tesseract version.

Options:
  --driver|-d {name}  Specify VM driver software, either of [docker].
  --build|-b          Build testable images if provided, otherwise pull images.
  --no-cache|-c       Build testable images without layer cache (only available with -b)
  --push|-p           Push local images to dockerhub (for development purpose).
  --quiet|-q          Don't show verbose logs of setting VMs up.
  --run|-R {case}     Run only cases which have specified pattern in the case names.
  --exclude|-X {case} Run only cases which DON'T have specified pattern in the case names.
  --rm                Remove VMs which are created by this runtime test.
  --list|-l           Just list runtimes
  --help|-h           Show this message ;)

Examples:

  ./test/runtime -d docker -v --run CentOS --rm

EOF
}
# }}}

# {{{ Parse CLI options
function parse_options() {
  DRIVER=
  REMOVE=
  BUILD=
  NO_CACHE=
  PUSH=
  QUIET=
  MATCH=
  EXCLUDE=
  LIST=
  while [[ $# -gt 0 ]]; do
  case "${1}" in
      --driver|-d)
      DRIVER="${2}"
      shift && shift
      ;;
      --rm)
      REMOVE=YES
      shift
      ;;
      --build|-b)
      BUILD=YES
      shift
      ;;
      --no-cache|-c)
      NO_CACHE="--no-cache"
      shift
      ;;
      --push|-p)
      PUSH=YES
      shift
      ;;
      --quiet|-q)
      QUIET="--quiet"
      shift
      ;;
      --run|-R)
      MATCH="${2}"
      shift && shift
      ;;
      --exclude|-X)
      EXCLUDE="${2}"
      shift && shift
      ;;
      --list|-l)
      LIST=YES
      shift
      ;;
      --help|-h)
      help && exit 0
      ;;
      *)
      printf "Unkown flag: ${1}\n\n"
      help
      exit 1
      ;;
  esac
  done
}
# }}}

# {{{ Runner function for "--driver docker"
function test_docker_runtimes() {
  if [ -n "${LIST}" ]; then
    echo "Available runtimes (docker):"
    for runtime in `ls ${PROJDIR}/test/runtimes/*.Dockerfile`; do
      testcase=`basename ${runtime} | sed -e s/\.Dockerfile$//`
      echo "  ${testcase}"
    done
    return 0
  fi

  for runtime in `ls ${PROJDIR}/test/runtimes/*.Dockerfile`; do
    testcase=`basename ${runtime} | sed -e s/\.Dockerfile$//`
    if [ -n "${MATCH}" ]; then
      if [[ "${testcase}" != *${MATCH}* ]]; then
        continue
      fi
    fi
    if [ -n "${EXCLUDE}" ]; then
      if [[ "${testcase}" == *${EXCLUDE}* ]]; then
        continue
      fi
    fi
    echo "┌───────────── ${testcase}"
    # q: Is following line correct?
    # XXX: Since clearlinux docker image doesn't support ARM64 architecture, as of 2024-07-26a,
    #      we need to add `--platform linux/amd64` to the `docker build` command when we build it on macos M3 chip.
    # if [ ${testcase} == "clearlinux" ]; then DOCKER_PLATFORM_ARG="--platform linux/amd64"; fi
    if [ -n "${BUILD}" ]; then
      echo "│ [Docker] Building image..."
      docker build . ${NO_CACHE} -f ${runtime} -t gosseract/test:${testcase} ${QUIET} | sed "s/^/│ /"
    else
      echo "│ [Docker] Pulling image..."
      docker pull gosseract/test:${testcase} ${QUIET} | sed "s/^/│ /"
    fi
    echo "│ [Docker] Running tests..."
    docker run -i -t -e "TESTCASE=${testcase}" --rm gosseract/test:${testcase} 1>./test/runtimes/TESTRESULT.${testcase}.txt 2>&1
    EXIT_CODE=$?
    cat ./test/runtimes/TESTRESULT.${testcase}.txt | sed "s/^/│ [${testcase}] /"
    if [ ${EXIT_CODE} -gt 0 ]; then
      printf "│ ${BOLD_RED}RUNTIME TEST FAILED! ${testcase}${RESET}\n"
      printf "└───────────── ${testcase} ${BOLD_RED}[NG]${RESET}\n"
      exit ${EXIT_CODE}
    fi
    if [ -n "${PUSH}" ]; then
      echo "│ [Docker] Pushing the image..."
      docker push gosseract/test:${testcase} | sed "s/^/│ /"
    fi
    if [ -n "${REMOVE}" ]; then
      echo "│ [Docker] Removing image..."
      docker rmi gosseract/test:${testcase} 1>/dev/null
    fi
    printf "└───────────── ${testcase} ${BOLD_GREEN}[OK]${RESET}\n"
  done
}
# }}}

# {{{ Runner function for "--driver vagrant"
# function test_vagrant_runtimes() {
#   if [ -n "${LIST}" ]; then
#     echo "Available runtimes (vagrant):"
#     for runtime in `ls ${PROJDIR}/test/runtimes/*.Vagrantfile`; do
#       testcase=`basename ${runtime} | sed -e s/\.Vagrantfile$//`
#       echo "  ${testcase}"
#     done
#     return 0
#   fi
# 
#   for runtime in `ls ${PROJDIR}/test/runtimes/*.Vagrantfile`; do
#     testcase=`basename ${runtime} | sed -e s/\.Vagrantfile$//`
#     if [ -n "${MATCH}" ]; then
#       if [[ "${testcase}" != *${MATCH}* ]]; then continue; fi
#     fi
#     echo "┌───────────── ${testcase}"
#     echo "│ [Vagrant] Making VM up..."
#     vboxname=gosseract-test-${testcase}
#     VAGRANT_VAGRANTFILE=${runtime} VIRTUALBOX_NAME=${vboxname} vagrant up ${VAGRANT_DEBUG} --provision --provider virtualbox # | sed "s/^/│ /"
#     TESTRESULT="${?}"
#     echo "[DEBUG] VAGRANT_VAGRANTFILE: " ${runtime}
#     echo "[DEBUG] VIRTUALBOX_NAME:     " ${vboxname}
#     VAGRANT_VAGRANTFILE=${runtime} VIRTUALBOX_NAME=${vboxname} vagrant ssh-config
#     echo "[DEBUG] ssh"
#     VAGRANT_VAGRANTFILE=${runtime} VIRTUALBOX_NAME=${vboxname} vagrant ssh -c "echo 'Hello, world!'"
#     echo "[DEBUG] /end"
#     if [ "${TESTRESULT}" != "0" ]; then
#       echo "│ [Vagrant] An error detected while upping VM"
#     fi
#     echo "│ [Vagrant] Stopping VM..."
#     VAGRANT_VAGRANTFILE=${runtime} vagrant halt # | sed "s/^/│ /"
#     if [ -n "${REMOVE}" ]; then
#       echo "│ [Vagrant] Removing VM..."
#       VAGRANT_VAGRANTFILE=${runtime} vagrant destroy -f # | sed "s/^/│ /"
#     fi
#     if [ "${TESTRESULT}" != "0" ]; then
#       printf "│ ${BOLD_RED}RUNTIME TEST FAILED! ${testcase}${RESET}\n"
#       printf "└───────────── ${testcase} ${BOLD_RED}[NG]${RESET}\n"
#       exit 1
#     fi
#     printf "└───────────── ${testcase} ${BOLD_GREEN}[OK]${RESET}\n"
#   done
# }
# }}}

# {{{ Main procedure
function __main__() {
  parse_options $@
  case ${DRIVER} in
    docker)
    test_docker_runtimes
    ;;
    # vagrant)
    # test_vagrant_runtimes
    # ;;
    *)
    test_docker_runtimes
    # test_vagrant_runtimes
    ;;
  esac
}
# }}}

# Entrypoint
__main__ $@
